#include <linux/fs.h>
#include <linux/io.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/uaccess.h>

struct digit4info {
	struct miscdevice misc;
	struct spi_device* spi;
};

ssize_t digit4_write(struct file * filp, const char __user * buf, size_t size, loff_t * offset)
{
	int error;
	struct spi_message message;
	struct spi_transfer xfer;
	uint16_t poscode;
	struct digit4info* info = filp->private_data;

	copy_from_user(&poscode, buf, sizeof(poscode));

	spi_message_init(&message);
	memset(&xfer, 0, sizeof(xfer));
	xfer.tx_buf = &poscode;
	xfer.len = sizeof(poscode);
	spi_message_add_tail(&xfer, &message);

	error = spi_sync(info->spi, &message);
	if (error)
	{
		return error;
	}

	return size;
}

struct file_operations digit4_fops = {
	.write = digit4_write,
};

static int digit4_probe(struct spi_device *spi)
{
	struct digit4info *info = devm_kmalloc(&spi->dev, sizeof(struct digit4info), GFP_KERNEL);
	if (!info)
	{
		return -ENOMEM;
	}

	info->spi        = spi;
	info->misc.minor = MISC_DYNAMIC_MINOR;
	info->misc.name  = "digit4";
	info->misc.fops  = &digit4_fops;
	misc_register(&info->misc);

	spi_set_drvdata(spi, info);

	printk("digit4 initialized\n");

	return 0;
}

static int digit4_remove(struct spi_device *spi)
{
	struct digit4info* info = spi_get_drvdata(spi);
	misc_deregister(&info->misc);
	return 0;
}

static const struct of_device_id digit4_matches[] = {
	{.compatible = "digit4", },
	{},
};

static struct spi_driver digit4_drv = {
	.driver =
	{
		.name = "digit4",
		.of_match_table = digit4_matches,
	},
	.probe = digit4_probe,
	.remove = digit4_remove,
};

module_spi_driver(digit4_drv);

MODULE_LICENSE("GPL");

